/**********************************************************************************************
    This class simulate the effects of an attack on the network
**********************************************************************************************/


using namespace std;


class SimulateAttack
{
private:
	
	//structure to save the attacks history in pairs <timeOfStartAttack, <attackType, attackStringDescription>> 
    list <pair < time_t, pair < string, string > > > AttackHistory;
	string StringEncoding (string attackType, list < pair<int, int> > ASsOriginAndAmount, int ASVictim);
	void StringDecoding (pair < string, string >, list < pair<int, int> > *ASsOriginAndAmount, int *ASVictim);

public:
	
	SimulateAttack();
	void PrintAttackHistory();	
	time_t StartDOSAttack( int ASOrigin, int ASVictim, int amount, TrafficNet *traffic );
	time_t StartDDOSAttack( list < pair<int, int> > ASsOriginAndAmount, int ASVictim, TrafficNet *traffic);
	void StopAttack( time_t timeOfAttack, TrafficNet *traffic);
};


SimulateAttack::SimulateAttack() 
{
;
}


/**********************************************************************************************
The method StringEncoding generate a string that describe the attack type and its input data,
this string is used in the AttackHistory structure to save a "hash function" history attack. 
**********************************************************************************************/ 
string SimulateAttack::StringEncoding (string attackType, list < pair<int, int> > ASsOriginAndAmount, int ASVictim)
{
	std::stringstream tmp;
	string attackStrDesc;
		
	/*
	A DOS encoding string where AS: 5 attack with 4 unit traffic amount the AS 10 will be: 
	#ASOrigin and amount:(5,4)@ASVictim:10#
	A DDOS encoding string where AS: 5,6,7 attack with 2 unit traffic amount the AS 10 will be: 
	#ASOrigin and amount:(5,2)(6,2)(7,2)@ASVictim:10#
	*/	 
	if (attackType == "DOS" or attackType == "DDOS")
	{
		attackStrDesc.insert(attackStrDesc.length(), "#ASOrigin and amount:");
		list < pair<int, int> >::iterator i;
		for (i = ASsOriginAndAmount.begin(); i != ASsOriginAndAmount.end(); i++)
		{
			/*
			For each pair of ASOrigin and amount of traffic convert it into string like 
			(ASOrigin1,amount1)...(ASOriginN,amountN) and append it on the AttackStrDesc string.
			*/
			attackStrDesc.insert(attackStrDesc.length(), "(");
			tmp.str(""); tmp << (*i).first;
			attackStrDesc.insert(attackStrDesc.length(), tmp.str());
			attackStrDesc.insert(attackStrDesc.length(), ",");
			tmp.str(""); tmp << (*i).second;
			attackStrDesc.insert(attackStrDesc.length(), tmp.str());		
			attackStrDesc.insert(attackStrDesc.length(), ")");
		}
		/*
		append to AttackStrDesc the ASVictim of attack ASvictim:number
		*/
		tmp.str(""); tmp << ASVictim;
		attackStrDesc.insert(attackStrDesc.length(),"@ASVictim:");
		attackStrDesc.insert(attackStrDesc.length(), tmp.str());
		attackStrDesc.insert(attackStrDesc.length(),"#");
	}
	return attackStrDesc;
}


/**********************************************************************************************
The method StringDecoding get a pair of string <attackType, attackStrDesc> where attackType 
is (DOS, DDOS, ...) and the attackStrDesc string that describe an attack saved in the 
"hash function" history attack. As output this method encoding these informations in form of 
data attack structures (ASsOriginAndAmount and ASVictim) to be used in the interaction with 
the structure.
**********************************************************************************************/ 
void SimulateAttack::StringDecoding (pair < string, string > attack, list < pair<int, int> > *ASsOriginAndAmount, int *ASVictim)
{
	list < pair < int, int> > l;
	std::stringstream tmp;
	string attackStrDesc;
	string attackType;

	tmp.str(""); tmp << attack.first;
	attackType = tmp.str();
	tmp.str(""); tmp << attack.second;
	attackStrDesc = tmp.str();


	if (attackType == "DOS" or attackType == "DDOS")
	{
		size_t parenthesisOpen, parenthesisClose, comma, snail, colon, sharp;

		parenthesisOpen = attackStrDesc.find_first_of("(");
		comma = attackStrDesc.find_first_of(",");
		parenthesisClose = attackStrDesc.find_first_of(")");
		snail = attackStrDesc.find_first_of("@");
		/*
		Decoding the pairs of (ASOrigin,amount) in form of list <int, int>
		*/
		while(parenthesisClose < snail)
		{
			string ASOriginStr = attackStrDesc.substr(parenthesisOpen+1, comma-parenthesisOpen-1);
			string amountStr = attackStrDesc.substr(comma+1, parenthesisClose-comma-1);

			int ASOrigin, amount;
			stringstream(ASOriginStr) >> ASOrigin;
			stringstream(amountStr) >> amount;

			
			l.push_back(make_pair (ASOrigin, amount));
			
			parenthesisOpen = attackStrDesc.find_first_of("(", parenthesisClose+1);
			comma = attackStrDesc.find_first_of(",", parenthesisClose+1);
			parenthesisClose = attackStrDesc.find_first_of(")", parenthesisClose+1);
		}
		/*
		Decoding the ASVictim in form of int
		*/
		colon = attackStrDesc.find_first_of(":", snail+1);
		sharp = attackStrDesc.find_first_of("#", snail+1);
		string ASVictimStr = attackStrDesc.substr(colon+1, sharp-colon-1);

		int ASVictimInt;
		stringstream(ASVictimStr) >> ASVictimInt;

		*ASVictim = ASVictimInt;
		ASsOriginAndAmount = &l;
	} 
}


/**********************************************************************************************
The method PrintAttackHistory print the list of attacks in execution. 
**********************************************************************************************/ 
void SimulateAttack::PrintAttackHistory()
{
	cout << "TIME OF ATTACK\t";
	cout << "TYPE\t";
	cout << "ATTACK DESCRIPTION\n";
	list <pair < long int, pair < string, string > > >::iterator i;
	for (i = AttackHistory.begin(); i != AttackHistory.end(); i++)
	{
		time_t seconds = (*i).first;
		string 	attackType = (*i).second.first;
		string 	attackStrDesc = (*i).second.second;
		cout << seconds << "\t"; 
		cout << attackType << "\t";
		cout << attackStrDesc << "\n";
    }
}


/**********************************************************************************************
The methods StartDOSAttack and StopDOSAttack take as input parameters the AS that starts the 
attack and the AS victim of this attack, they also take as input parameters the amount of 
generated traffic to start/stop a DOS attack. The effect of the attack is simulated by 
adding/subtracting "dos" type traffic to the TrafficNet matrix that contain the amount of 
traffics between each pair of ASs.
The method return as value the timeOfAttack as unique "hash" number corresponding the attack.
**********************************************************************************************/
time_t SimulateAttack::StartDOSAttack( int ASOrigin, int ASVictim, int amount, TrafficNet *traffic )
{
	list < pair<int, int> > tmp;
	time_t seconds = time (NULL);
	string attackType = "DOS";
	string attackStrDesc;

	tmp.push_back (make_pair(ASOrigin, amount));
	attackStrDesc = StringEncoding (attackType, tmp, ASVictim);
	AttackHistory.push_back (make_pair(seconds, make_pair(attackType, attackStrDesc)));
	traffic->addTraffic( ASOrigin, ASVictim, "dos", amount );
	return seconds;
}


/**********************************************************************************************
The method StartDDOSAttack takes as input parameters the AS list that starts the attack
and the rispective amount of generated traffic to start the DDOS attack, it also take as input
the AS victim of this attack. The effect of the attack is simulated by adding "dos" type 
traffic to the TrafficNet matrix that contain the amount of traffics between each pair of ASs.
The method return as value the timeOfAttack as unique "hash" number corresponding the attack.
**********************************************************************************************/
time_t SimulateAttack:: StartDDOSAttack( list < pair<int, int> > ASsOriginAndAmount, int ASVictim, TrafficNet *traffic)
{
	time_t seconds = time (NULL);
	string attackType = "DDOS";
	string attackStrDesc;

	attackStrDesc = StringEncoding (attackType, ASsOriginAndAmount, ASVictim);
	list < pair<int, int> >::iterator i;
	for (i = ASsOriginAndAmount.begin(); i != ASsOriginAndAmount.end(); i++)
	{
		int ASOrigin = (*i).first;
		int amount = (*i).second;
		traffic->addTraffic( ASOrigin, ASVictim, "dos", amount );
    }
	AttackHistory.push_back (make_pair (seconds, make_pair(attackType, attackStrDesc)));
	return seconds;
}


/**********************************************************************************************
The method stopAttack takes as input the time of attack, decoding thecorresponding string and 
 then stops the attack based on the information saved in the "hash function".
**********************************************************************************************/
void SimulateAttack:: StopAttack( time_t timeOfAttack, TrafficNet *traffic)
{
	string attackType;
	string attackStrDesc;

	list < pair<int, int> > ASsOriginAndAmount;
	int ASVictim;

	list <pair < long int, pair < string, string > > >::iterator i;
	for (i = AttackHistory.begin(); i != AttackHistory.end(); i++)
	{
		time_t seconds = (*i).first;
		if (seconds == timeOfAttack)
		{
			attackType = (*i).second.first;
			attackStrDesc = (*i).second.second;
			StringDecoding (make_pair (attackType, attackStrDesc), &ASsOriginAndAmount, &ASVictim);
			AttackHistory.erase(i);
			break;
		}
    }

	list < pair<int, int> >::iterator j;
	for (j = ASsOriginAndAmount.begin(); j != ASsOriginAndAmount.end(); j++)
	{
		int ASOrigin = (*j).first;
		int amount = (*j).second;
		traffic->subTraffic( ASOrigin, ASVictim, "dos", amount );
    }
}